/*
 * Bit array hashtable wrapper implementation
 */
#include <stdlib.h>
#include <stdbool.h>
#include <stdint.h>
#include "contracts.h"
#include "xalloc.h"
#include "bitarray.h"
#include "ht.h"
#include "ba-ht.h"

//get the key from an elem
ht_key get_key_from_elem(ht_elem e){
    struct ba_ht_elem_base *elem = (struct ba_ht_elem_base *)e;
    return (void *)(&elem->ba);
}

//check whether two key are equal
bool check_key_equal(ht_key k1, ht_key k2){
    return bitarray_equal(*(bitarray *)k1, *(bitarray *)k2);
} 

//get the hash value of key
size_t get_hash_value(ht_key k){
    size_t h = 0;
    for(uint8_t i = 0; i < BITARRAY_LIMIT; ++i){
        size_t num = 0;
        if(bitarray_get(*(bitarray *)k, i)){
            num = 1;
        }
        h = h + (num << i);
    }
    return h;
}

/* Creates a new hash table
 */
ht ba_ht_new(size_t capacity){
    REQUIRES(0 < capacity);
    ht new = ht_new(capacity,
                    &get_key_from_elem,
                    &check_key_equal,
                    &get_hash_value,
                    &free);
    ENSURES(new != NULL);
    return new;
}


/* insert into an hashtable
 */
void ba_ht_insert(ht H, ba_ht_elem e){
    REQUIRES(H != NULL);
    ENSURES(ht_lookup(H, &e->ba) == NULL);
    ht_elem he = ht_insert(H, (void *)e);
    if(he != NULL){
        free(he);
    }
    return;
}

/* ht_lookup(H,k) returns 
 * NULL if no element with key k exists and
 * the element associated with the key otherwise.
 * NULL keys are invalid in ba_hts
 */
ba_ht_elem ba_ht_lookup(ht H, ba_ht_key k){
    REQUIRES(H != NULL);
    ba_ht_elem res = ht_lookup(H, (void*)k);
    if(res != NULL){
        return res;
    }
    return NULL;
}

/* Frees the hash table and all of its data
 */
void ba_ht_free(ht H){
    if(H != NULL){
        ht_free(H);
    }
    return;
}